package com.mega.center.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.mega.center.system.mapper.MenuMapper;
import com.mega.center.system.model.entity.Menu;
import com.mega.center.system.model.vo.MenuTreeVO;
import com.mega.center.system.model.vo.UserModuleMenuVO;
import com.mega.center.system.service.IMenuService;
import com.mega.center.system.service.IModuleService;
import com.mega.common.core.constant.Constants;
import com.mega.common.core.constant.UserConstants;
import com.mega.common.core.enums.CommonMsgEnum;
import com.mega.common.core.exception.BusinessException;
import com.mega.common.core.utils.TreeUtil;
import com.mega.common.core.web.model.KeyValue;
import com.mega.common.core.web.model.TreeNodeSelect;
import com.mega.common.core.web.service.MegaBaseServiceImpl;
import com.mega.common.redis.utils.CodeUtils;
import com.mega.common.security.utils.SecurityUtils;
import com.mega.system.api.vo.ModuleVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单表 服务实现
 *
 * @author Eric
 * @version 1.0
 * @since 2020-09-23
 */
@Service
public class MenuServiceImpl extends MegaBaseServiceImpl<MenuMapper, Menu> implements IMenuService {

    @Autowired
    private IModuleService moduleService;

    /**
     * 新增菜单表
     *
     * @param menu 菜单表实体类
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(Menu menu) {
        String parentCode = StrUtil.isBlank(menu.getParentMenuCode()) ? UserConstants.DEFAULT_TREE_ROOT_CODE : menu.getParentMenuCode();
        Integer nameCount = this.count(Wrappers.<Menu>lambdaQuery()
                .eq(Menu::getSystemCode, menu.getSystemCode())
                .eq(Menu::getParentMenuCode, parentCode)
                .eq(Menu::getMenuName, menu.getMenuName()));
        if (nameCount != null && nameCount > 0) {
            throw new BusinessException(CommonMsgEnum.NAME_REPEAT, menu.getMenuName());
        }
        menu.setMenuCode(CodeUtils.getDateCode(menu));
        //设置父节点编码
        Menu parentMenu = getMenuByCode(parentCode);
        menu.setParentMenuCode(parentCode);
        menu.setParentMenuCodes((StrUtil.isBlank(parentMenu.getParentMenuCodes()) ? "" : parentMenu.getParentMenuCodes()) + parentCode + Constants.COMMA_SEPARATOR);
        menu.setTreeLevel(parentMenu.getTreeLevel() + 1);
        //插入数据
        this.save(menu);
    }

    /**
     * 根据编码获取菜单信息
     *
     * @param code
     * @return
     */
    @Override
    public Menu getMenuByCode(String code) {
        if (UserConstants.DEFAULT_TREE_ROOT_CODE.equals(code)) {
            Menu menu = new Menu();
            menu.setMenuCode(UserConstants.DEFAULT_TREE_ROOT_CODE);
            menu.setMenuName("ROOT");
            menu.setTreeLevel(0);
            return menu;
        } else {
            return this.getOne(Wrappers.<Menu>lambdaQuery()
                    .eq(Menu::getMenuCode, code));
        }
    }

    /**
     * 编辑菜单表
     *
     * @param menu 菜单表实体类
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Menu menu) {
        //判断数据是否为空
        Menu queryEntity = this.getById(menu.getId());
        if (queryEntity == null) {
            throw new BusinessException(CommonMsgEnum.DATE_NOT_EXIST);
        }
        //查询修改后名称是否与原先一致
        if (!menu.getMenuName().equals(queryEntity.getMenuName())) {
            //判断名称是否重复
            Integer nameCount = this.count(Wrappers.<Menu>lambdaQuery()
                    .eq(Menu::getSystemCode, menu.getSystemCode())
                    .eq(Menu::getParentMenuCode, menu.getParentMenuCode())
                    .eq(Menu::getMenuName, menu.getMenuName()));
            if (nameCount != null && nameCount > 0) {
                throw new BusinessException(CommonMsgEnum.NAME_REPEAT, menu.getMenuName());
            }
        }
        //判断是否变更上级
        String parentCode = StrUtil.isBlank(menu.getParentMenuCode()) ? UserConstants.DEFAULT_TREE_ROOT_CODE : menu.getParentMenuCode();
        if (!parentCode.equals(queryEntity.getParentMenuCode())) {
            Menu parentMenu = getMenuByCode(parentCode);
            String newParentCodes = (StrUtil.isBlank(parentMenu.getParentMenuCodes()) ? "" : parentMenu.getParentMenuCodes()) + parentCode + Constants.COMMA_SEPARATOR;
            String oldChildParentCodes = queryEntity.getParentMenuCodes() + queryEntity.getMenuCode() + Constants.COMMA_SEPARATOR;
            String newChildParentCodes = newParentCodes + queryEntity.getMenuCode() + Constants.COMMA_SEPARATOR;
            int oldLevel = queryEntity.getTreeLevel();
            int newLevel = parentMenu.getTreeLevel() + 1;
            //变更子节点父节点集合
            List<Menu> childs = this.list(Wrappers.<Menu>lambdaQuery().likeRight(Menu::getParentMenuCodes, oldChildParentCodes));
            if (CollectionUtil.isNotEmpty(childs)) {
                childs.forEach(v -> {
                    v.setParentMenuCodes(v.getParentMenuCodes().replace(oldChildParentCodes, newChildParentCodes));
                    v.setTreeLevel(v.getTreeLevel() + newLevel - oldLevel);
                });
                this.updateBatchById(childs);
            }
            menu.setParentMenuCode(parentCode);
            menu.setParentMenuCodes(newParentCodes);
            menu.setTreeLevel(newLevel);
        }
        //更新数据
        this.updateById(menu);
    }

    /**
     * 根据id删除菜单表
     *
     * @param id 主键值
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Integer id) {
        this.removeById(id);
    }

    /**
     * 获取单个系统菜单:选择组件
     *
     * @return
     */
    @Override
    public List<TreeNodeSelect> listSystemMenuForSelect(String systemCode) {
        List<TreeNodeSelect> menuList = this.baseMapper.listSystemAllMenusForSelect(systemCode);
        return TreeUtil.buildTree(menuList, UserConstants.DEFAULT_TREE_ROOT_CODE);
    }

    /**
     * 获取单个系统菜单
     *
     * @return
     */
    @Override
    public List<MenuTreeVO> listSystemMenu(String systemCode) {
        List<MenuTreeVO> menuList = this.baseMapper.listSystemAllMenus(systemCode);
        return TreeUtil.buildTree(menuList, UserConstants.DEFAULT_TREE_ROOT_CODE);
    }

    /**
     * 获取授权菜单数据
     *
     * @return
     */
    @Override
    public List<ModuleVO> listModuleMenu() {
        List<ModuleVO> moduleList = moduleService.listSystemModule();
        if (CollectionUtil.isNotEmpty(moduleList)) {
            moduleList.forEach(module -> {
                module.setMenuData(listSystemMenuForSelect(module.getModuleCode()));
            });
        }
        return moduleList;
    }

    /**
     * 获取用户模块，菜单，权限
     *
     * @param userName
     * @return
     */
    @Override
    public UserModuleMenuVO getUserModuleAndMenuInfo(String userName) {
        UserModuleMenuVO userModuleMenuVO = new UserModuleMenuVO();
        //获取用户模块数据
        List<ModuleVO> userModuleList = moduleService.listUserModule(userName);
        userModuleMenuVO.setModules(userModuleList);

        //根据用户所拥有模块获取菜单以及权限
        if (CollectionUtil.isNotEmpty(userModuleList)) {
            Set<String> userModuleCodes = userModuleList.stream().map(ModuleVO::getModuleCode).collect(Collectors.toSet());
            //获取用户菜单信息
            userModuleMenuVO.setMenus(this.getUserMenuByModules(userName, userModuleCodes));
            //获取用户权限信息
            userModuleMenuVO.setPermissions(this.getUserPermissionByModules(userName, userModuleCodes));
        }
        return userModuleMenuVO;
    }

    /**
     * 按模块获取用户菜单权限
     *
     * @param userName
     * @param systemCode
     * @return
     */
    @Override
    public UserModuleMenuVO getUserMenuInfoByModule(String userName, String systemCode) {
        UserModuleMenuVO userModuleMenuVO = new UserModuleMenuVO();
        Set<String> userModuleCodes = new HashSet<>();
        userModuleCodes.add(systemCode);
        //获取用户菜单信息
        userModuleMenuVO.setMenus(this.getUserMenuByModules(userName, userModuleCodes));
        //获取用户权限信息
        userModuleMenuVO.setPermissions(this.getUserPermissionByModules(userName, userModuleCodes));
        return userModuleMenuVO;
    }

    /**
     * 根据系统模块获取用户菜单
     *
     * @param userName
     * @param userModuleCodes
     * @return
     */
    @Override
    public Map<String, List<MenuTreeVO>> getUserMenuByModules(String userName, Set<String> userModuleCodes) {
        Map<String, List<MenuTreeVO>> userMenuMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(userModuleCodes)) {
            List<MenuTreeVO> userMenuList = null;
            if (SecurityUtils.isAdmin(userName)) {
                userMenuList = this.baseMapper.listMenuByModule(userModuleCodes);
            } else {
                userMenuList = this.baseMapper.listUserMenu(userName, userModuleCodes);
            }
            Map<String, List<MenuTreeVO>> systemMenuMap = userMenuList.stream().collect(Collectors.groupingBy(MenuTreeVO::getSystemCode));
            if (CollectionUtil.isNotEmpty(systemMenuMap)) {
                systemMenuMap.forEach((k, v) -> {
                    userMenuMap.put(k, TreeUtil.buildTree(v, UserConstants.DEFAULT_TREE_ROOT_CODE));
                });
            }
        }
        return userMenuMap;
    }

    /**
     * 根据系统模块获取用户权限
     *
     * @param userName
     * @param userModuleCodes
     * @return
     */
    @Override
    public Map<String, Set<String>> getUserPermissionByModules(String userName, Set<String> userModuleCodes) {
        Map<String, Set<String>> userPermissionMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(userModuleCodes)) {
            if (SecurityUtils.isAdmin(userName)) {
                Set<String> perms = new HashSet<>();
                perms.add(UserConstants.ALL_PERMISSION);
                userModuleCodes.forEach(k -> {
                    userPermissionMap.put(k, perms);
                });
            } else {
                List<KeyValue> permissionList = this.baseMapper.getUserMenuPermission(userName, userModuleCodes);
                Map<String, List<KeyValue>> permissionMap = permissionList.stream().collect(Collectors.groupingBy(KeyValue::getKey));
                if (CollectionUtil.isNotEmpty(permissionMap)) {
                    permissionMap.forEach((k, v) -> {
                        userPermissionMap.put(k, v.stream().map(KeyValue::getValue).collect(Collectors.toSet()));
                    });
                }
            }
        }
        return userPermissionMap;
    }
}
